package com.esdk.utils;

import com.alibaba.fastjson.JSONPath;
import com.esdk.esdk;
import com.esdk.sql.Exp;
import lombok.NonNull;
import org.jdom.Document;
import org.jdom.Element;
import org.nutz.lang.Files;
import org.nutz.repo.Base64;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.OutputStream;
import java.util.*;
import java.util.regex.Pattern;

public class EasyDoc{
	private File _templateFile; //后缀名为doc，但内容为xml格式
	private Map<String,Object> params=new HashMap<>();
	private LinkedHashSet<String> imageKeys=new LinkedHashSet<>();
	private LimitedHashMap<String,String> imageCxCyMap=new LimitedHashMap<>();
	public EasyDoc(File docTemplateFile)throws FileNotFoundException{
		if(!docTemplateFile.exists())
			throw new FileNotFoundException(docTemplateFile.toString()+" is not found");
		this._templateFile=docTemplateFile;
	}
	
	public EasyDoc put(@NonNull String key,String value) {
		params.put(key,value);
		return this;
	}
	
	public EasyDoc put(@NonNull String key, Number value) {
		params.put(key,value+"");
		return this;
	}

	public EasyDoc put(@NonNull String key, Map map) {
		params.put(key,map);
		return this;
	}

	public EasyDoc put(@NonNull String key, File imgFile,int cx,int cy){
		return put(key,Files.readBytes(imgFile),cx,cy);
	}
	public EasyDoc put(@NonNull String key, String imgFilePath,int cx,int cy){
		if(esdk.str.isBlank(imgFilePath))
			return this;
		File imgFile=new File(imgFilePath);
		if(imgFile.exists()==false)
			return this;
		return put(key,Files.readBytes(imgFile),cx,cy);
	}

	public EasyDoc put(String key, byte[] bytes,int cx,int cy){
		imageKeys.add(key);
		imageCxCyMap.put(key,cx+","+cy);
		String base64str=binary2Base64(bytes);
		params.put(key,base64str);
		return this;
	}

	public static String convertCheckBoxValue(Boolean value){
		return value!=null&&value==true?"■":"□";
	}
	
	public static String convertRadioValue(Boolean value){
		return value!=null&&value==true?"●":"○";
	}

	public static String binary2Base64(byte[] bytes){
		return Base64.encodeToString(bytes,true);
	}

	public static String binary2Base64(File file){
		return binary2Base64(Files.readBytes(file));
	}

	private String parse() throws Exception{
		String docXmlStr=EasyFile.loadFromFile(_templateFile,"utf-8");
		String regex="(\\$\\{)(.+?)(\\})";
		String content=esdk.regex.replaceAll(docXmlStr,regex,Pattern.CASE_INSENSITIVE|Pattern.DOTALL,m->{
			String key=m.group(2).replaceAll("<.*?>| ","");
			if(!imageKeys.isEmpty() && imageKeys.contains(key))
				return "${"+key+"}";
			String value=esdk.str.valueOf(params.get(key));
			if(value==null) {
				value = (String) JSONPath.eval(params, "$." + key);
			}
			return esdk.obj.or(value,"").replaceAll("\r?\n","<w:br w:type=\"textWrapping\"/>");
		});
		if(!imageKeys.isEmpty()){
			Document doc=esdk.jdom.str2Doc(content);
			for(String key:imageKeys){
				Element relationships=esdk.jdom.getChildByPath(doc.getRootElement(),"part[1]/xmlData/Relationships",true);
				Element clone=(Element)((Element)relationships.getChildren().get(0)).clone();
//				clone.setAttribute("Id",esdk.str.serial(clone.getAttributeValue("Id")));
				clone.setAttribute("Id",key);
				clone.setAttribute("Target","media/"+key+".jpeg");
				clone.setAttribute("Type","http://schemas.openxmlformats.org/officeDocument/2006/relationships/image");
				relationships.addContent(clone);
				List<Element> imageKeyList=esdk.jdom.findText(doc.getRootElement(),Exp.CONTAINS,key,null);
				Integer[] cxcy=esdk.math.toIntArray(imageCxCyMap.get(key).split(","));
				for(Element item:imageKeyList){
					item.getParentElement().addContent(getImageTempate(key,key,key,cxcy[0],cxcy[1]));
					item.detach();
					doc.getRootElement().addContent(getImageBase64Part(key,(String)params.get(key)));
				}
			}
			content=esdk.jdom.doc2Str(doc);
		}
		return content;
	}
	private Element getImageBase64Part(@NonNull String key,@NonNull String base64content) throws Exception{
		String content="<pkg:part pkg:name=\"/word/media/"+key
				+".jpeg\" pkg:contentType=\"image/jpeg\" xmlns:pkg=\"http://schemas.microsoft.com/office/2006/xmlPackage\">"
				+"<pkg:binaryData>"
				+base64content
				+"</pkg:binaryData></pkg:part>";
		Element result=esdk.jdom.str2Elment(content);
		result.detach();
		return result;
	}
	private Element getImageTempate(@NonNull String embed,@NonNull String name,@NonNull String descr,int cx,int cy) throws Exception{
		String template=esdk.file.loadFromFile(EasyDoc.class,"doc_image_template.xml");
		String eleStr=esdk.str.format(template,embed,name,descr,cx,cy);
		Element result=esdk.jdom.str2Elment(eleStr);
		result.detach();
		return result;
	}

	public boolean toDoc(@NonNull File outputFile)throws Exception{
		String content=parse();
		return esdk.file.saveToFile(content,outputFile,true,EasyFile.UTF8);
	}

	public void toPDF(@NonNull File pdfFile)throws Exception{
		File docFile=new File(pdfFile.getAbsolutePath().replaceFirst("\\.pdf",".doc"));
		if(!docFile.exists()){
			toDoc(docFile);
		}
		esdk.tool.exec("wps2pdf.exe "+docFile.getAbsolutePath()+" "+pdfFile.getAbsolutePath());//要先安装wps
		//TODO 如何删除临时文件.doc?
	}
	
	public File doc2pdf(@NonNull File docFile,@NonNull File pdfFile) throws Exception {
		if(pdfFile==null)
			pdfFile=new File(docFile.getAbsolutePath().replaceFirst("\\.docx?",".pdf"));
		esdk.tool.exec2Int("wps2pdf.exe "+docFile.getAbsolutePath()+" "+pdfFile.getAbsolutePath());//要先安装wps
		return pdfFile;
	}

	public byte[] toBytes() throws Exception {
		String content=parse();
		return content.getBytes();
	}

	public void writeTo(OutputStream os) throws Exception {
		String content=parse();
    os.write(content.getBytes());
    os.flush();
	}
	
	public Map<String, Object> getParams() {
		return params;
	}
	public static void main(String[] args) throws Exception{
		TimeMeter tm=new TimeMeter();
		File xmlFile=new File("./testfiles/设备输出报告_${nowDate}_(${name}).doc");
		esdk.tool.assertEquals(xmlFile.exists());
		Document doc=esdk.jdom.file2Doc(xmlFile);
		EasyDoc ed=new EasyDoc(xmlFile);
		ed.put("name","苏东坡");
		ed.put("损坏面积",760);
		ed.put("测试时长","7分钟");
		ed.put("year",2022);
		ed.put("白屏坏点个数",22);
		ed.put("绿屏坏点个数",11);
		ed.put("蓝牙功能检测","已通过");
		ed.put("GSM功能检测","未实现");
		ed.put("WiFi功能检测","未通过");

		ed.put("nowDate",esdk.time.format(new Date(),"yyyy-M-d"));
		ed.put("base",esdk.map.urlParamsToMap("brand=华为&type=P30Pro&屏幕尺寸=1980*1080&sn=SN000000001"));
		ed.put("imageWhiteScreenCheck",new File("./testfiles/scratch_103100_X116.7_Y109.7_Z153.5.jpg"),1642110,1094740);
		ed.put("imageGreenScreenCheck",new File("./testfiles/badpoint_show_2.jpg"),1600000,900000);

		File outputFile=new File(esdk.str.format(xmlFile.getAbsolutePath(),ed.params));
		ed.toDoc(outputFile); //输出doc
		ed.toPDF(esdk.file.replaceExtName(outputFile,"pdf")); //输出pdf
		tm.printElapse();
	}
}
